package com.lw.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.lw.common.enums.GlobalTypeEnum;
import com.lw.common.utils.GlobalConstants;
import com.lw.common.utils.StrUtils;
import com.lw.common.vo.Option;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.lw.entity.TbDept;
import com.lw.mapper.TbDeptMapper;
import com.lw.service.TbDeptService;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.lw.entity.table.TbDeptTableDef.TB_DEPT;

/**
 * 部门表 服务层实现。
 *
 * @author lw
 * @since 2025年05月15日 08:32:28
 */
@Service
public class TbDeptServiceImpl extends ServiceImpl<TbDeptMapper, TbDept> implements TbDeptService {

    @Override
    public List<Option<Long>> listDeptOptions() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(TB_DEPT.STATUS.getName(), GlobalTypeEnum.STATE_ENABLE.getValue());
        queryWrapper.select(TB_DEPT.ID, TB_DEPT.PARENT_ID, TB_DEPT.NAME);
        queryWrapper.orderBy(TB_DEPT.SORT.getName(), true);
        List<TbDept> deptList = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(deptList)) {
            return List.of();
        }

        Set<Long> deptIds = deptList.stream()
                .map(TbDept::getId)
                .collect(Collectors.toSet());

        Set<Long> parentIds = deptList.stream()
                .map(TbDept::getParentId)
                .collect(Collectors.toSet());

        List<Long> rootIds = CollectionUtil.subtractToList(parentIds, deptIds);

        // 递归生成部门树形列表
        return rootIds.stream()
                .flatMap(rootId -> recurDeptTreeOptions(rootId, deptList).stream())
                .toList();
    }

    @Override
    public List<TbDept> getDeptTree(TbDept dept) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.like(TB_DEPT.NAME.getName(), dept.getKeywords(), StrUtils.hasLength(dept.getKeywords()));
        queryWrapper.eq(TB_DEPT.STATUS.getName(), GlobalTypeEnum.STATE_ENABLE.getValue(), dept.getStatus() != null);
        queryWrapper.orderBy(TB_DEPT.SORT.getName());
        List<TbDept> deptList = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(deptList)) {
            return List.of();
        }
        //获取所有部门id集合
        Set<Long> deptIds = deptList.stream().map(TbDept::getId).collect(Collectors.toSet());
        //获取所有父部门id集合
        Set<Long> parentIds = deptList.stream().map(TbDept::getParentId).collect(Collectors.toSet());

        /*
         *  获取根节点ID（递归的起点），即父节点ID中不包含在部门ID中的节点，
         *  注意这里不能拿顶级部门 O 作为根节点，因为部门筛选的时候 O 会被过滤掉
         */
        List<Long> rootIds = CollectionUtil.subtractToList(parentIds, deptIds);
        // 递归生成部门树形列表
        return rootIds.stream()
               .flatMap(rootId -> recurDeptTree(rootId, deptList).stream())
               .toList();
    }

    @Override
    public Boolean saveDept(TbDept tbDept) {
         //检查部门编号是否存在
        String code = tbDept.getCode();
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.eq(TB_DEPT.CODE.getName(), code);
        long count = this.count(queryWrapper);
        Assert.isTrue(count == 0, "部门编号已存在");
        String treePath = generateDeptTreePath(tbDept.getParentId());
        tbDept.setTreePath(treePath);
        tbDept.setCreateBy(StpUtil.getLoginIdAsLong());
        boolean save = this.save(tbDept);
        Assert.isTrue(save, "添加部门失败");
        return true;
    }

    @Override
    public Long updateDept(TbDept tbDept) {
        //检查部门编号是否存在
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.eq(TB_DEPT.CODE.getName(), tbDept.getCode());
        queryWrapper.eq(TB_DEPT.ID.getName(), tbDept.getId());
        long count = this.count(queryWrapper);
        Assert.isTrue(count == 0, "部门编号已存在");
        String treePath = generateDeptTreePath(tbDept.getParentId());
        tbDept.setTreePath(treePath);

        //更新部门信息
        boolean b = this.updateById(tbDept);
        Assert.isTrue(b, "更新部门失败");
        return tbDept.getId();
    }

    @Override
    public Boolean deleteByIds(String ids) {
        // 删除部门及子部门
        if (StrUtil.isNotBlank(ids)) {
            String[] menuIds = ids.split(",");
            for (String deptId : menuIds) {
                QueryWrapper queryWrapper = QueryWrapper.create();
                queryWrapper.eq(TB_DEPT.ID.getName(), deptId);
                queryWrapper.or("FIND_IN_SET(#{value}, tree_path)", deptId);
                boolean remove = this.remove(queryWrapper);
                System.out.println(remove);
            }
        }
        return true;
    }

    private String generateDeptTreePath(Long parentId) {
        String treePath = null;
        if (GlobalConstants.ROOT_NODE_ID.equals(parentId)) {
            treePath = String.valueOf(parentId);
        } else {
            TbDept parent = this.getById(parentId);
            if (parent != null) {
                treePath = parent.getTreePath() + "," + parent.getId();
            }
        }
        return treePath;
    }

    public List<TbDept> recurDeptTree(Long parentId, List<TbDept> deptList) {
        return deptList.stream()
                .filter(dept -> dept.getParentId().equals(parentId))
                .map(dept -> {
                    List<TbDept> children = recurDeptTree(dept.getId(), deptList);
                    dept.setChildren(children);
                    return dept;
                }).toList();
    }

    /**
     * 递归生成部门表格层级列表
     *
     * @param parentId 父ID
     * @param deptList 部门列表
     * @return 部门表格层级列表
     */
    public static List<Option<Long>> recurDeptTreeOptions(long parentId, List<TbDept> deptList) {
        return CollectionUtil.emptyIfNull(deptList).stream()
                .filter(dept -> dept.getParentId().equals(parentId))
                .map(dept -> {
                    Option<Long> option = new Option<>(dept.getId(), dept.getName());
                    List<Option<Long>> children = recurDeptTreeOptions(dept.getId(), deptList);
                    if (CollectionUtil.isNotEmpty(children)) {
                        option.setChildren(children);
                    }
                    return option;
                })
                .collect(Collectors.toList());
    }

}
